﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace DXBase.Structs
{
	[StructLayout(LayoutKind.Sequential)]
	public struct Box2D : IHasBounds<Box2D>, IBounds
	{
		float x, y,width, height;

		public Box2D(float width, float height)
		{
			x = 0;
			y = 0;
			if (width < 0)
				throw new ArgumentOutOfRangeException("width");
			if (height < 0)
				throw new ArgumentOutOfRangeException("height");
			this.width = width;
			this.height = height;
		}
		public Box2D(float x, float width, float y, float height)
		{
			this.x = x;
			this.y = y;
			if (width < 0)
				throw new ArgumentOutOfRangeException("width");
			if (height < 0)
				throw new ArgumentOutOfRangeException("height");
			this.width = width;
			this.height = height;
		}
		public Box2D(params Vector2F[] points)
			: this((IEnumerable<Vector2F>)points)
		{
		}
		public Box2D(IEnumerable<Vector2F> points)
		{
			Vector2F min = new Vector2F();
			Vector2F max = new Vector2F();
			bool first = true;
			foreach (var p in points)
			{
				if (first)
				{
					first = false;
					min = max = p;
				}
				else
				{
					if (p.X < min.X)
						min.X = p.X;
					if (p.X > max.X)
						max.X = p.X;
					if (p.Y < min.Y)
						min.Y = p.Y;
					if (p.Y > max.Y)
						max.Y = p.Y;
				}
			}
			x = min.X;
			width = max.X - min.X;
			y = min.Y;
			height = max.Y - min.Y;
		}

		public static implicit operator Windows.Foundation.Rect(Box2D r) { return new Windows.Foundation.Rect(r.x, r.y, r.width, r.height); }
		public static implicit operator Box2D(Windows.Foundation.Rect r) { return new Box2D((float)r.X, (float)r.Width, (float)r.Y, (float)r.Height); }

		public float X
		{
			get { return x; }
			set { x = value; }
		}
		public float Y
		{
			get { return y; }
			set { y = value; }
		}
		public float XMax { get { return x + width; } }
		public float YMax { get { return y + height; } }
		public float Width
		{
			get { return width; }
			set
			{
				if (value < 0)
					throw new ArgumentOutOfRangeException();
				width = value;
			}
		}
		public float Height
		{
			get { return height; }
			set
			{
				if (value < 0)
					throw new ArgumentOutOfRangeException();
				height = value;
			}
		}
		public Vector2F Center { get { return new Vector2F(x + width / 2, y + height / 2); } }


		bool IBounds.Intersects(IBounds b) { return Intersects((Box2D)b); }
		public bool Intersects(Box2D r)
		{
			return
				X <= r.XMax
				&& XMax >= r.X
				&& Y <= r.YMax
				&& YMax >= r.Y
				;
		}

		bool IBounds.Contains(IBounds b) { return Contains((Box2D)b); }
		public bool Contains(Box2D r)
		{
			return
				X <= r.X
				&& XMax >= r.XMax
				&& Y <= r.Y
				&& YMax >= r.YMax
				;
		}

		Box2D IHasBounds<Box2D>.Bounds { get { return this; } }
		float IBounds.MaxLength { get { return Math.Max(width, height); } }

		public override string ToString()
		{
			return string.Format("Box2D({0}, {1})", new Vector2F(x, y), new Vector2F(XMax, YMax));
		}
	}

}
